home *** CD-ROM | disk | FTP | other *** search
- /*
- * f1to0.c 4/30/89
- *
- * Author: Michael S. Czeiszperger
- * Purpose: The program converts format 1 MIDI files to format 0
- * MIDI files. It is meant to demonstrate the use of
- * the midifile library. The internal data format is
- * a linked list of MIDI and SMF meta events.
- *
- * The spec is available from:
- * International MIDI Association
- * 5316 West 57th Street
- * Los Angeles, CA 90056
- *
- * An in-depth description of the spec can also be found
- * in the article "Introducing Standard MIDI Files", published
- * in Electronic Musician magazine, April, 1988.
- *
- * usage: f1to0 infile outfile
- *
- */
-
- #include <stdio.h>
- #include <ctype.h>
-
- #ifdef THINK
- #include <stdlib.h>
- #else
- #include <malloc.h>
- #endif
-
- #include "midifile.h"
-
- enum PACKET_TYPE { MIDI_EVENT, META_EVENT };
-
- struct MIDIpacket /* Stucture for MIDI events */
- {
- enum PACKET_TYPE p_type; /* What type of packet is it? */
- unsigned long time; /* absolute time of event, in ms increments */
- unsigned int m_type; /* What kind of MIDI message? */
- unsigned int chan; /* The MIDI channel */
- unsigned long len; /* length of the midi message */
- unsigned char *data; /* pointer to the data */
- struct MIDIpacket *next,*before; /* point to next packet */
- } *sequence_start,*sequence_end;
-
- /*
- This example structure is not very portable. It does, however,
- mirror the logical operation of the header, and on some machines can
- be written and read directly. It assumes that shorts are at least
- two bytes and chars are at least one byte.
- */
- struct header_type {
- short format;
- short ntrks;
- union {
- short quarter_note;
- struct{
- char format;
- char resolution;
- } smpte;
- } division;
- } header;
-
- /* These lines are needed to use the library */
- FILE *fpIn,*fpOut;
- extern long Mf_currtime;
- mygetc() { return(getc(fpIn)); }
- myputc(c) { return(putc(c,fpOut));}
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- /* This is included of an example of what to do if you use THINK C on
- the mac. */
- #ifdef THINK
- #include <console.h>
- argc = ccommand(&argv);
- #endif
-
- if((fpIn = fopen(argv[1],"r")) == 0L)
- printf("f1to0: unable to open file %s for reading.\n",argv[1]);
-
- if((fpOut = fopen(argv[2],"w")) == 0L)
- printf("f1to0: unable to open file %s for writing.\n",argv[2]);
-
- init_funcs();
-
- /* read the midi file */
- mfread();
-
- /* write a single track */
- mfwrite((int)header.format,1,(int)header.division.quarter_note,fpOut);
- }
-
- myheader(format,ntrks,division)
- int format,ntrks,division;
- {
- header.format = format;
- header.ntrks = ntrks;
- header.division.quarter_note = division;
- }
-
- myerror(s)
- char *s;
- {
- printf("%10ld: %s\n",Mf_currtime,s);
- }
-
- /*
- * mywritetrack()
- *
- * Sample showing how to use the library routines to write out a track.
- * Returns 1 if successful, and -1 if not.
- *
- */
- int mywritetrack(track)
- int track;
- {
- struct MIDIpacket *current;
- unsigned long delta_time;
-
- current = sequence_start; /* init to point at the beginning of the list */
-
- /* shuffle through each element in the linked list, writing out
- the data in the standard MIDI format */
- while(current != 0L)
- {
- if(current == sequence_start)
- delta_time = current->time;
- else
- delta_time = current->time - (current->before)->time;
- #ifdef DEBUG
- printf("ticks = %lu event = %d packet = %d chan = %d len = %lu\n",
- current->time,current->m_type,current->p_type,current->chan,current->len);
- #endif
-
- if(current->p_type == MIDI_EVENT)
- {
- if(mf_write_midi_event(delta_time,current->m_type,current->chan,current->data,current->len) < 0)
- return(-1);
- }
- else if(current->p_type == META_EVENT)
- {
- if(mf_write_meta_event(delta_time,current->m_type,current->data,current->len) < 0)
- return(-1);
- }
- else
- fprintf(stderr,"Unknown MIDI packet encounted.\n");
-
- current = current->next;
- }
- return(1);
- } /* end of write_track() */
-
-
- /*
- * This routine adds a MIDI or META event into the linked list.
- */
- void add_packet(ticks,event_type,packet_type,chan,data,len)
- unsigned long ticks; /* absolute ticks of event */
- int event_type; /* note_on, note_off, etc */
- enum PACKET_TYPE packet_type; /* What kind of data? */
- unsigned char *data; /* already allocated data */
- unsigned long len; /* length of data */
- {
- struct MIDIpacket *scratch,*insert_pt,*get_insert_point();
-
- #ifdef DEBUG
- printf("ticks = %d event = %d packet = %d chan = %d len = %d\n",ticks,event_type,packet_type,chan,len);
- #endif
- scratch = (struct MIDIpacket *) malloc(sizeof(struct MIDIpacket));
-
- if(scratch == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
-
- scratch->data = data;
- scratch->m_type = event_type;
- scratch->p_type = packet_type;
- scratch->chan = chan;
- scratch->len = len;
- scratch->time = ticks;
-
- /* Where in the linked list should this packet go? */
- insert_pt = get_insert_point(sequence_start,sequence_end,ticks);
-
- if(sequence_start == 0L) /* the list is empty */
- {
- sequence_start = sequence_end = scratch;
- scratch->before = 0L;
- scratch->next = 0L;
- }
- else if(insert_pt == 0L) /* insert the new bottom record */
- {
- sequence_end->next = scratch;
- scratch->before = sequence_end;
- scratch->next = 0L;
- sequence_end = scratch;
- }
- else if(insert_pt == sequence_start) /* insert the new top record */
- {
- sequence_start->before = scratch;
- scratch->before = 0L;
- scratch->next = sequence_start;
- sequence_start = scratch;
- }
- else /* insert before the insert pointer */
- {
- scratch->next = insert_pt;
- scratch->before = insert_pt->before;
- insert_pt->before = scratch;
- (scratch->before)->next = scratch;
- }
- } /* end of add_packet() */
-
- /*
- * get_insert_point()
- * A routine to help insertion into a linked list,
- * by returning a pointer to the position in the list
- * where the MIDI packet should be inserted based on
- * the time the MIDI event occurs. This could be a lot
- * faster, but was left simple for easy debugging.
- * If you'd like to speed this up, please go ahead!
- */
- struct MIDIpacket *get_insert_point(top,bottom,time)
- struct MIDIpacket *top,*bottom;
- unsigned long time;
- {
- struct MIDIpacket *index;
- /* this keeps track of the last inset point, making it easier */
- /* to find the next one assuming that most times will be */
- /* consecutive. */
- static struct MIDIpacket *insert_pointer;
-
- if(top == 0L || bottom == 0L) return(0L);
- if(time > bottom->time) return(0L); /* tack onto end of list */
- if(time < top->time) return(top); /* insert as the new first record */
-
- /* check around where the last packet was inserted */
- if(insert_pointer != 0L)
- index = insert_pointer;
- else
- {
- index = sequence_start;
- insert_pointer = index;
- }
- if(time > index->time)
- {
- while(time > index->time && index != 0L)
- index = index->next;
- return(index);
- }
- else if(time < index->time)
- {
- while(time < index->time && index != 0L)
- index = index->before;
- return(index->next);
- }
- else
- return(insert_pointer);
- } /* end of get_insert_point() */
-
- /* Routines called from midifile lib */
- mynoteon(chan,c1,c2)
- int chan,c1,c2;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) c1;
- data[1] = (unsigned char) c2;
- add_packet((unsigned long)Mf_currtime,note_on,MIDI_EVENT,chan,data,(unsigned long)2);
- }
-
- mynoteoff(chan,c1,c2)
- int chan,c1,c2;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) c1;
- data[1] = (unsigned char) c2;
- add_packet((unsigned long)Mf_currtime,note_off,MIDI_EVENT,chan,data,(unsigned long)2);
- }
-
- mypressure(chan,pitch,pressure)
- int chan,pitch,pressure;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) pitch;
- data[1] = (unsigned char) pressure;
- add_packet((unsigned long)Mf_currtime,poly_aftertouch,MIDI_EVENT,chan,data,(unsigned long)2);
- }
-
- mykeypressure(chan,pitch,pressure)
- int chan,pitch,pressure;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) pitch;
- data[1] = (unsigned char) pressure;
- add_packet((unsigned long)Mf_currtime,channel_aftertouch,MIDI_EVENT,chan,data,(unsigned long)2);
- }
-
- myparameter(chan,control,value)
- int chan,control,value;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) control;
- data[1] = (unsigned char) value;
- add_packet((unsigned long)Mf_currtime,control_change,MIDI_EVENT,chan,data,(unsigned long)2);
- }
-
- mytempo(microsecs)
- unsigned long microsecs;
- {
- unsigned char *data;
- data = (unsigned char *) malloc(sizeof(char) * 3);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[2] = (unsigned)(microsecs & 0xff);
- data[1] = (unsigned)((microsecs >> 8) & 0xff);
- data[0] = (unsigned)((microsecs >> 16) & 0xff);
- add_packet((unsigned long)Mf_currtime,set_tempo,META_EVENT,0,data,(unsigned long)3);
- }
-
- myvarlen(type,len,msg)
- int type,len;
- char *msg;
- {
- unsigned char *data;
- int i;
-
- data = (unsigned char *) malloc((unsigned)(sizeof(char) * len));
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- for(i = 0; i < len; i++)
- data[i] = msg[i];
- add_packet((unsigned long)Mf_currtime,type,META_EVENT,0,data,(unsigned long)len);
- }
-
- mysmpte(hour,min,sec,frame,fract)
- char hour,min,sec,frame,fract;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 5);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = hour;
- data[1] = min;
- data[2] = sec;
- data[3] = frame;
- data[4] = fract;
- add_packet((unsigned long)Mf_currtime,smpte_offset,META_EVENT,0,data,(unsigned long)5);
- }
-
- myprogram(chan,program)
- int chan, program;
- {
- unsigned char *data;
- data = (unsigned char *) malloc(sizeof(char) * 1);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) program;
- add_packet((unsigned long)Mf_currtime,program_chng,MIDI_EVENT,chan,data,(unsigned long)1);
- }
-
- mypitchbend(chan,msb,lsb)
- int chan, msb,lsb;
- {
- unsigned char *data;
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) msb;
- data[1] = (unsigned char) lsb;
- add_packet((unsigned long)Mf_currtime,pitch_wheel,MIDI_EVENT,chan,data,(unsigned long)2);
- }
-
- mysysex(len,msg)
- int len;
- char *msg;
- {
- unsigned char *data;
- int i;
-
- data = (unsigned char *) malloc((unsigned)(sizeof(char) * len));
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- for(i = 0; i < len; i++)
- data[i] = msg[i];
- add_packet((unsigned long)Mf_currtime,system_exclusive,MIDI_EVENT,0,data,(unsigned long)len);
- }
-
- myseqnum(num)
- int num;
- {
- unsigned char *data;
- data = (unsigned char *) malloc(sizeof(char) * 1);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = (unsigned char) num;
- add_packet((unsigned long)Mf_currtime,sequence_number,META_EVENT,0,data,(unsigned long)1);
- }
-
- mytimesig(numer,denom,clocks,qnotes)
- char numer,denom,clocks,qnotes;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 4);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = numer;
- data[1] = denom;
- data[2] = clocks;
- data[3] = qnotes;
- add_packet((unsigned long)Mf_currtime,time_signature,META_EVENT,0,data,(unsigned long)4);
- }
-
- mykeysig(sharpflat, minor)
- int sharpflat, minor;
- {
- unsigned char *data;
-
- data = (unsigned char *) malloc(sizeof(char) * 2);
- if(data == NULL)
- {
- fprintf(stderr,"Sorry, out of memory!\n");
- exit(1);
- }
- data[0] = sharpflat;
- data[1] = minor;
- add_packet((unsigned long)Mf_currtime,key_signature,META_EVENT,0,data,(unsigned long)2);
- }
-
- init_funcs()
- {
- sequence_start = 0L;
- sequence_end = 0L;
-
- /* needed for reading */
- Mf_getc = mygetc;
- Mf_error = myerror;
- Mf_header = myheader;
- Mf_noteon = mynoteon;
- Mf_noteoff = mynoteoff;
- Mf_pressure = mypressure;
- Mf_parameter = myparameter;
- Mf_pitchbend = mypitchbend;
- Mf_program = myprogram;
- Mf_chanpressure = mykeypressure;
- Mf_sysex = mysysex;
- Mf_metamisc = myvarlen;
- Mf_seqspecific = myvarlen;
- Mf_seqnum = myseqnum;
- Mf_text = myvarlen;
- Mf_timesig = mytimesig;
- Mf_smpte = mysmpte;
- Mf_tempo = mytempo;
- Mf_keysig = mykeysig;
-
- /* needed for writing */
- Mf_putc = myputc;
- Mf_writetrack = mywritetrack;
- }
-